#ifndef __LOG_H__
#define __LOG_H__

#include <stdint.h>
#include <string.h>

#define LOG_LEVEL_DEBUG 0
#define LOG_LEVEL_INFO 1
#define LOG_LEVEL_WARN 2
#define LOG_LEVEL_ERROR 3
#define LOG_LEVEL_FATAL 4

#define LOG_LEVEL_NUM 5 // 日志级别数量

#define LOG_BUFFER_SIZE 256 // 日志snprintf缓冲区大小,即一次性最大输出长度

// 日志配置
#define ENABLE_LOG 1 // 是否开启日志, 1: 开启, 0: 关闭
#define LOG_LEVEL LOG_LEVEL_DEBUG // 日志级别, DEBUG: 打印所有日志, INFO: 打印INFO以上级别日志, WARN: 打印WARN以上级别日志, ERROR: 打印ERROR以上级别日志, FATAL: 打印FATAL级别日志
#define USE_BASE_LINE 1 // 是否使用相对路径, 1: 使用, 0: 不使用

#define USING_FUNCTION 1 // 是否使用函数名, 1: 使用, 0: 不使用
#define USING_FILE 1 // 是否使用文件名, 1: 使用, 0: 不使用
#define USING_LINE 1 // 是否使用行号, 1: 使用, 0: 不使用

typedef enum _log_mode {
    LOG_MODE_NORMAL = 0,    // 普通模式
    LOG_MODE_IT             // 中断模式
} LogMode;

typedef enum _log_fmt_type {
    LOG_FMT_LEVEL = 1 << 0, // 日志级别
    LOG_FMT_TIME = 1 << 1,  // 时间
    LOG_FMT_FILE = 1 << 2,  // 文件名
    LOG_FMT_FUNC = 1 << 3,  // 函数名
    LOG_FMT_LINE = 1 << 4,  // 行号
} LogFmtType;

#define LOG_FMT_ALL (LOG_FMT_LEVEL | LOG_FMT_TIME | LOG_FMT_FILE | LOG_FMT_FUNC | LOG_FMT_LINE) // 所有格式

// 设置去除FILE前缀路径宏定义
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
// 是否使用函数名
#ifdef USING_FUNCTION
    #define LOG_OUTPUT_FUNC __FUNCTION__
#else
    #define LOG_OUTPUT_FUNC ""
#endif
// 是否使用文件名
#ifdef USING_FILE
    #if (USE_BASE_LINE == 1)    // 去除FILE前缀路径
        #define LOG_OUTPUT_DIR __FILENAME__
    #else
        #define LOG_OUTPUT_DIR __FILE__
    #endif
#else
    #define LOG_OUTPUT_DIR ""
#endif
// 是否使用行号
#ifdef USING_LINE
    #define LOG_OUTPUT_LINE __LINE__
#else
    #define LOG_OUTPUT_LINE 0
#endif

#if (ENABLE_LOG == 1)
    #if (LOG_LEVEL <= LOG_LEVEL_DEBUG)
        #define LOG_DEBUG(format, ...)  \
                log_output(LOG_MODE_NORMAL, LOG_LEVEL_DEBUG, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
        #define LOG_DEBUG_IT(format, ...)   \
                log_output(LOG_MODE_IT, LOG_LEVEL_DEBUG, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
    #else
        #define LOG_DEBUG(format, ...)
        #define LOG_DEBUG_IT(format, ...)
    #endif
    #if (LOG_LEVEL <= LOG_LEVEL_INFO)
        #define LOG_INFO(format, ...)   \
                log_output(LOG_MODE_NORMAL, LOG_LEVEL_INFO, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
        #define LOG_INFO_IT(format, ...)   \
                log_output(LOG_MODE_IT, LOG_LEVEL_INFO, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
    #else
        #define LOG_INFO(format, ...)
        #define LOG_INFO_IT(format, ...)
    #endif
    #if (LOG_LEVEL <= LOG_LEVEL_WARN)
        #define LOG_WARN(format, ...)   \
                log_output(LOG_MODE_NORMAL, LOG_LEVEL_WARN, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
        #define LOG_WARN_IT(format, ...)   \
                log_output(LOG_MODE_IT, LOG_LEVEL_WARN, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
    #else
        #define LOG_WARN(format, ...)
        #define LOG_WARN_IT(format, ...)
    #endif
    #if (LOG_LEVEL <= LOG_LEVEL_ERROR)
        #define LOG_ERROR(format, ...)  \
                log_output(LOG_MODE_NORMAL, LOG_LEVEL_ERROR, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
        #define LOG_ERROR_IT(format, ...)   \
                log_output(LOG_MODE_IT, LOG_LEVEL_ERROR, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
    #else
        #define LOG_ERROR(format, ...)
        #define LOG_ERROR_IT(format, ...)
    #endif
    #if (LOG_LEVEL <= LOG_LEVEL_FATAL)
        #define LOG_FATAL(format, ...)  \
                log_output(LOG_MODE_NORMAL, LOG_LEVEL_FATAL, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
        #define LOG_FATAL_IT(format, ...)   \
                log_output(LOG_MODE_IT, LOG_LEVEL_FATAL, LOG_OUTPUT_DIR, LOG_OUTPUT_FUNC, LOG_OUTPUT_LINE, format"\r\n", ##__VA_ARGS__)
    #else
        #define LOG_FATAL(format, ...)
        #define LOG_FATAL_IT(format, ...)
    #endif
#else
    #define LOG_DEBUG(format, ...)
    #define LOG_DEBUG_IT(format, ...)
    #define LOG_INFO(format, ...)
    #define LOG_INFO_IT(format, ...)
    #define LOG_WARN(format, ...)
    #define LOG_WARN_IT(format, ...)
    #define LOG_ERROR(format, ...)
    #define LOG_ERROR_IT(format, ...)
    #define LOG_FATAL(format, ...)
    #define LOG_FATAL_IT(format, ...)
#endif

void log_init(void);
void log_set_all_fmt(void);
void log_set_fmt(uint8_t level, uint16_t type);
void log_clear_fmt(uint8_t level, uint16_t type);
uint8_t log_output(LogMode mode, uint8_t level, const char *file, const char *func,
                    const long line, const char *format, ...);
void log_disable(void);
void log_enable(void);

#endif
